package fr.univ.lille1.android;

import android.app.Activity;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentTransaction;
import fr.univ.lille1.android.auth.AuthenticationService;
import fr.univ.lille1.android.auth.OnConnectionFailedTagThis;
import fr.univ.lille1.android.auth.OnConnectionTagThis;
import fr.univ.lille1.android.auth.TagThisClient;

public class AuthenticationFragment extends Fragment {
	/**
	 * Tag to refer to this fragment.
	 */
	private static final String TAG_AUTHENTICATION = "AuthenticationFragment";

	/**
	 * Authentication service. This can be TagThis or Google Plus
	 * authentication.
	 */
	private AuthenticationService mAuthenticationService;
	/**
	 * Tracks if the authentication is launched.
	 */
	private boolean mIsConnecting;

	/**
	 * Attach the fragment at the activity host if it isn't already attached.
	 * 
	 * @param activity
	 *            Activity host of the fragment.
	 * @return AuthenticationFragment instance
	 */
	public static AuthenticationFragment get(FragmentActivity activity) {
		if (!(activity instanceof OnSignInListener)) {
			throw new IllegalArgumentException(
					"The activity must implement OnSignedInListener to receive callbacks.");
		}

		// Check if the fragment is already attached.
		final FragmentManager fm = activity.getSupportFragmentManager();
		final Fragment fragment = fm.findFragmentByTag(TAG_AUTHENTICATION);
		if (fragment instanceof AuthenticationFragment) {
			return (AuthenticationFragment) fragment;
		}

		final FragmentTransaction ft = fm.beginTransaction();
		// If the fragment is already attached, remove it to clean up.
		if (fragment != null) {
			ft.remove(fragment);
		}

		// Create a new fragment and attach it to the fragment manager.
		AuthenticationFragment authenticationFragment = new AuthenticationFragment();
		ft.add(authenticationFragment, TAG_AUTHENTICATION);
		ft.commit();
		return authenticationFragment;
	}

	/**
	 * Listener interface for sign in events. Activities hosting a
	 * {@link AuthenticationFragment } must implement this listener.
	 */
	public interface OnSignInListener {
		/**
		 * Called when the {@link AuthenticationService } has been connected
		 * successfully.
		 * 
		 * @param service
		 *            The connected {@link AuthenticationService } to make
		 *            requests on.
		 */
		void onSignedIn(AuthenticationService service);

		/**
		 * Called when the {@link AuthenticationService } fails to connect.
		 */
		void onSignInFailed();
	}

	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		// Retain instance to avoid reconnecting on rotate.
		setRetainInstance(true);

		// Create TagThis authentication. TODO create the authenticated service
		// desired with the authentication factory.
		mAuthenticationService = new TagThisClient(getActivity()
				.getApplicationContext(), mOnConnectionTagThis,
				mOnConnectionFailedTagThis);
	}

	/**
	 * Sign In with token of the session in {@link SharedPreferences}.
	 */
	public void connect() {
		mAuthenticationService.connection();
		mIsConnecting = true;
	}

	/**
	 * Sign In with e-mail and password.
	 * 
	 * @param email
	 *            E-mail of the user.
	 * @param password
	 *            Password of the user.
	 */
	public void signIn(String email, String password) {
		mAuthenticationService.connection(email, password);
		mIsConnecting = true;
	}

	/**
	 * Disconnect the user.
	 */
	public void disconnect() {
		mAuthenticationService.disconnection();
	}

	/**
	 * Callback about the TagThis authentication connection.
	 */
	private final OnConnectionTagThis mOnConnectionTagThis = new OnConnectionTagThis() {

		@Override
		public void onDisconnected() {
		}

		@Override
		public void onConnected() {
			mIsConnecting = false;

			Activity activity = getActivity();
			if (activity instanceof OnSignInListener) {
				((OnSignInListener) activity)
						.onSignedIn(mAuthenticationService);
			}
		}
	};

	/**
	 * Callback about the failed TagThis authentication.
	 */
	private final OnConnectionFailedTagThis mOnConnectionFailedTagThis = new OnConnectionFailedTagThis() {

		@Override
		public void onConnectionFailed() {
			mIsConnecting = false;

			Activity activity = getActivity();
			if (activity instanceof OnSignInListener) {
				((OnSignInListener) activity).onSignInFailed();
			}
		}
	};

	/**
	 * Check if the user is authenticated with {@link AuthenticationService}.
	 * 
	 * @return true if the user is connected.
	 */
	public boolean isAuthenticated() {
		return mAuthenticationService != null
				&& mAuthenticationService.isConnected();
	}

	/**
	 * Check if the user is connecting.
	 * 
	 * @return true if the user is connecting.
	 */
	public boolean isConnecting() {
		return mIsConnecting;
	}

	/**
	 * Get client of the {@link AuthenticationService}.
	 * 
	 * @return {@link AuthenticationService} implementation.
	 */
	public AuthenticationService getClient() {
		return mAuthenticationService;
	}
}
